package com.ubing.boot.notesforjava.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ubing.boot.notesforjava.annotation.JsonConvert;
import org.apache.poi.ss.formula.functions.T;
import org.aspectj.weaver.ast.Var;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

public class ConvertUtils {

    private final  static String DEFAULT_GX= "DEFAULT_GX";

    /***
    * @Title: convert
    * @Param: [from, to]
    * @description:
    * @author: ubing
    * @date:  2023/5/10/20:35
    * @return: T
    * @throws:
    */

    public static <T> T convert(@NotNull Object from, @NotNull Class<T> to) {
        Field[] toFields = to.getDeclaredFields();
        Class<?> fromClass = from.getClass();
        T toObj = null;
        try {
            toObj = to.newInstance();
            for (Field toField : toFields) {
                JsonConvert convert = toField.getAnnotation(JsonConvert.class);
                if (convert != null) {
                    toField.setAccessible(true);
                    Field fromField;
                    String value = convert.value();
                    if (DEFAULT_GX.equals(value)) value=toField.getName();
                    fromField = fromClass.getDeclaredField(value);
                    fromField.setAccessible(true);
                    Object fromVal = fromField.get(from);
                    Class<?> fieldType = toField.getType();
                    if(String.class.equals(fieldType)) toField.set(toObj,fromVal);
                    else if(Integer.class.equals(fieldType)) toField.set(toObj,Integer.parseInt(String.valueOf(fromVal)));
                    else if(double.class.equals(fieldType)) toField.set(toObj,Double.parseDouble(String.valueOf(fromVal)));
                }
            }
        } catch (InstantiationException | IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
        } finally {
            return toObj;
        }
    }

    /***
    * @Title: convert
    * @Param: [fromList, to]
    * @description:
    * @author: ubing
    * @date:  2023/5/10/20:35
    * @return: java.util.List<T>
    * @throws:
    */
    @Nullable
    public static <T> List<T> convert(@NotNull List fromList, Class<T> to) {
        if(fromList.size()==0) return null;
        Object fromObj = fromList.get(0);
        Class<?> fromClazz = fromObj.getClass();
        Field[] declaredFields = to.getDeclaredFields();
        List<Field> fieldList = Arrays.stream(declaredFields)
                .filter((item) -> item.getAnnotation(JsonConvert.class) != null)
                .collect(Collectors.toList());
        ArrayList<T> arrayList = new ArrayList();
        for (Object o : fromList) {
            try {
                T toObj = to.newInstance();
                for (Field convertField : fieldList) {
                    Class<?> type = convertField.getType();
                    convertField.setAccessible(true);
                    checkTypeForObject(toObj,convertField,type,fromClazz,o);
                }
                arrayList.add(toObj);
            } catch (InstantiationException | IllegalAccessException | NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
        return arrayList;
    }

    /***
    * @Title: jsonConvert
    * @Param: [jsonObj, to]
    * @description: 基于fastjson2封装方法
    * @author: ubing
    * @date:  2023/5/10/20:35
    * @return: T
    * @throws:
    */
    public static <T> T jsonConvert(JSONObject jsonObj, @NotNull Class<T> to) {
        Field[] toFields = to.getDeclaredFields();
        T toObj = null;
        try {
            toObj = to.newInstance();
            for (Field toField : toFields) {
                JsonConvert jsonConvert = toField.getAnnotation(JsonConvert.class);
                if(jsonConvert != null){
                    toField.setAccessible(true);
                    Object jsonVal;
                    if (DEFAULT_GX.equals(jsonConvert.value())) {
                        jsonVal = jsonObj.get(toField.getName());
                    } else {
                        jsonVal=jsonObj.get(jsonConvert.value());
                    }
                    checkTypeForJson(toObj,toField,jsonVal);
                }
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            return toObj;
        }
    }

    /***
    * @Title: jsonConvert
    * @Param: [fromList, to]
    * @description: 基于fastjson2封装方法
    * @author: ubing
    * @date:  2023/5/10/20:35
    * @return: java.util.List<T>
    * @throws:
    */
    @Nullable
    public static <T> List<T> jsonConvert(@NotNull List<JSONObject> fromList, Class<T> to) {
        if(fromList.size()==0) return null;
        Field[] toDeclaredFields = to.getDeclaredFields();
        List<Field> toFields = Arrays.stream(toDeclaredFields).filter(item -> item.getAnnotation(JsonConvert.class) != null).collect(Collectors.toList());
        ArrayList<T> arrayList = new ArrayList<>();
        for (JSONObject object : fromList) {
            try {
                T toObj = to.newInstance();
                for (Field toField : toFields) {
                    JsonConvert jsonConvert = toField.getAnnotation(JsonConvert.class);
                    toField.setAccessible(true);
                    String value = jsonConvert.value();
                    if(DEFAULT_GX.equals(value)) value = toField.getName();
                    checkTypeForJson(toObj,toField,object.get(value));
                }
                arrayList.add(toObj);
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return arrayList;
    }

    // 转映射的json
    public static String toJson(@NotNull Object object){
        JSONObject json = new JSONObject();
        Field[] declaredFields = object.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            if(field.getAnnotation(JsonConvert.class)!=null){
                JsonConvert annotation = field.getAnnotation(JsonConvert.class);
                field.setAccessible(true);
                try {
                    objectToJson(annotation,field,object,json);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return JSON.toJSONString(json);
    }

    //
    private static <T> void  checkTypeForObject(T toObj, @NotNull Field convertField, Class<?> type, @NotNull Class<?> fromClazz, Object o) throws IllegalAccessException, NoSuchFieldException {
        String value = convertField.getAnnotation(JsonConvert.class).value();
        if(DEFAULT_GX.equals(value)) value=convertField.getName();
        Field declaredField = fromClazz.getDeclaredField(value);
        declaredField.setAccessible(true);
        if(String.class.equals(type)) convertField.set(toObj,declaredField.get(o));
        else if(Integer.class.equals(type)) convertField.set(toObj,Integer.parseInt(String.valueOf(declaredField.get(o))));
        else if(double.class.equals(type)) convertField.set(toObj,Double.parseDouble(String.valueOf(declaredField.get(o))));
    }

    // jsonConvert判断类型赋值
    private static <T> void  checkTypeForJson(T toObj, @NotNull Field toField, Object jsonVal) throws IllegalAccessException {
        Class<?> fieldType = toField.getType();
        if(String.class.equals(fieldType)) toField.set(toObj,jsonVal);
        else if(Integer.class.equals(fieldType)) toField.set(toObj,Integer.parseInt(String.valueOf(jsonVal)));
        else if(double.class.equals(fieldType)) toField.set(toObj,Double.parseDouble(String.valueOf(jsonVal)));
    }

    // jsonConvert判断类型赋值
    private static void objectToJson(JsonConvert jsonConvert, Field field, Object obj, LinkedHashMap<String, Object> json) throws IllegalAccessException {
        field.setAccessible(true);
        Class<?> clazz = jsonConvert.jsonType();
        String value = jsonConvert.value();
        if(DEFAULT_GX.equals(value)) value=field.getName();
        if(String.class.equals(clazz)) {
            json.put(value,field.get(obj));
        } else if(Integer.class.equals(clazz)) {
            json.put(value,Integer.parseInt(String.valueOf(field.get(obj))));
        } else if(Double.class.equals(clazz)) {
            json.put(value,Double.parseDouble(String.valueOf(field.get(obj))));
        }
    }
}
